#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Version: Python 2.6.6
# Author: Sergey K.
# Created: 2011-09-14


import unittest
import json

import common

import rs
import rs.resource
import rs.message

from rs.context import context_property, Context
from rs.resource import ResourceManager
from rs.request import Request
from rs.response import Response


class ContextTest(unittest.TestCase):

    def setUp(self):
        @rs.post
        @rs.path('/rs/tests/{method}/{id}')
        @rs.consumes('application/json', json.loads)
        @rs.produces('application/json; charset="windows-1251"', json.dumps)
        def testres(id,
            m=rs.context.alias('method','method_'),
            e=rs.context.entity,
            u=rs.context.uri):
            return [{'response': (id, m, e, u)}]
        @rs.error(405)
        @rs.produces('application/json; charset="windows-1251"', json.dumps)
        def testerr():
            return [{'error': 'Method Not Allowed'}]
        self.testres, self.testerr = testres, testerr
        self.res = rs.resource.build(testres)[0]
        self.req = common.request()
        self.req.method = 'POST'
        self.req.uri = '/rs/tests/ADD/1'
        self.req.entity = '{"ENTITY":"YES"}'
        self.req.headers['content-length'] = str(len(self.req.entity))
        self.req.headers['content-type'] = 'application/json'
        self.srv = common.server(dummy_bases=ResourceManager)
        self.srv.server_properties = 'server properties'
        self.params = common.params()
        self.params.path['method'] = 'ADD'
        self.params.path['id'] = '1'
        self.ctx = rs.context(self.srv, self.req)
        self.ctx._resource = self.res
        self.ctx._params = self.params

    def tearDown(self):
        from rs.error import ErrorManager
        ErrorManager.error_handlers.clear()

    def test_entity(self):
        self.assertEquals(json.loads(self.req.entity), self.ctx.entity)

    def test_request(self):
        self.assertEqual(self.req, self.ctx.request)

    def test_uri(self):
        self.assertEqual(self.req.uri, self.ctx.uri)

    def test_alias(self):
        self.assertEquals('ADD', rs.context.alias('method').__get__(self.ctx))
        self.assertEquals('1', rs.context.alias('id').__get__(self.ctx))
        self.assertEquals('DEFAULT', rs.context.alias('method_', default='DEFAULT').__get__(self.ctx))
        try:
            rs.context.alias('method_').__get__(self.ctx)
        except ValueError as e:
            pass
        else:
            self.fail('ValueError expected.')

    def test_resolve_params(self):
        params = dict(self.ctx.resolve_params(self.res))
        eq = self.assertEquals
        eq('ADD', params['m'])
        eq('1', params['id'])
        eq(json.loads(self.req.entity), params['e'])

    def test_resolve_params_empty_entity(self):
        self.req.entity = None
        del self.req.headers['content-length']
        params = dict(self.ctx.resolve_params(self.res))
        eq = self.assertEquals
        eq('ADD', params['m'])
        eq('1', params['id'])
        eq(None, params['e'])

    def test_resolve_params_bad_request_if_bad_entity(self):
        try:
            self.req.entity = repr(object)
            self.req.headers['content-length'] = len(self.req.entity)
            self.req.headers['content-type'] = 'text/plain'
            dict(self.ctx.resolve_params(self.res))
        except rs.error as e:
            self.assertEquals(rs.status.BAD_REQUEST, e.status)
        else:
            self.fail('400 status expected.')

    def test_resolve_params_bad_request_if_not_enough_args(self):
        try:
            self.ctx._params = common.params()
            self.ctx._params.path = {}
            self.ctx._params.query['id'] = 1
            dict(self.ctx.resolve_params(self.res))
        except rs.error as e:
            self.assertEquals(rs.status.BAD_REQUEST, e.status)
        else:
            self.fail('400 status expected.')

    def test_get_response(self):
        true = self.assertTrue
        eq = self.assertEquals
        from rs.application import WSGIApplication
        app = WSGIApplication([self.testres])
        r = Request()
        r.method = 'POST'
        r.uri = rs.message.uri('/rs/tests/ADD/1', '')
        response = Context(app, r).get_response()
        true(isinstance(response, Response))
        eq(200, response.status)
        r.method = 'GET'
        response = Context(app, r).get_response()
        true(isinstance(response, Response))
        eq(405, response.status)
        eq(json.dumps(self.testerr()), response.entity)
        r.uri = rs.message.uri('/sr/tests/ADD/1', '')
        response = Context(app, r).get_response()
        true(isinstance(response, rs.error))
        eq(404, response.status)

        
class ContextDataTest(unittest.TestCase):

    def test_nonzero(self):
        self.assertFalse(rs.context.entity)
        self.assertFalse(rs.context.request)
        self.assertFalse(rs.context.uri)
        self.assertFalse(rs.context.alias)

    def test_call(self):
        def test_prop(prop):
            p = prop()
            self.assertTrue(isinstance(prop, context_property))
            self.assertTrue(isinstance(p, context_property))
            self.assertFalse(p is prop)
            self.assertFalse(p)
        test_prop(rs.context.entity)
        test_prop(rs.context.request)
        test_prop(rs.context.uri)
        test_prop(rs.context.alias)


if __name__ == '__main__':
    unittest.main()